﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Diagnostics;

namespace IBNet.UtilsDataStructuresAndExtensions
{
   /// <summary>
   /// A HashSet&lt;T> that is observed by a specified ListView. Adds and removes to and from the HashSet&lt;T> are also performed on the ListView observer.
   /// </summary>
   /// <typeparam name="T">The type of elements in the hashset.</typeparam>
   public class ListViewObservableThreadSafeHashSet<T> : IDisposable
   {
      private readonly ThreadSafeHashSet<T> hashSet;
      private readonly ListView listViewObserver;

      /// <summary>
      /// Creates a new ListViewObservableHashSet&lt;T> with a specified ListView observer.
      /// </summary>
      /// <param name="listView">The ListView observer of the underlying HashSet&lt;T></param>
      public ListViewObservableThreadSafeHashSet(ListView listViewObserver)
      {
         this.hashSet = new ThreadSafeHashSet<T>();
         this.listViewObserver = listViewObserver;
      }

      /// <summary>
      /// Creates a new ListViewObservableHashSet&lt;T> with no ListView observer.
      /// </summary>
      public ListViewObservableThreadSafeHashSet()
      {
         this.hashSet = new ThreadSafeHashSet<T>();
      }

      /// <summary>
      /// Gets the number of elements in the ListViewObservableThreadSafeHashSet&lt;T>.
      /// </summary>
      public int Count
      {
         get { return hashSet.Count; } 
      }

      /// <summary>
      /// Adds the specified element to the HashSet&lt;T>. 
      /// Once added, this item will appear in the ListView observer.
      /// </summary>
      /// <param name="item">The element to add to the HashSet&lt;T>.</param>
      /// <returns>True if the element is added successfully; otherwise, false. This method returns false if the element is already present in the HashSet&lt;T>.</returns>
      public bool Add(T item)
      {
         bool didAddItemSuccessfully = hashSet.Add(item);
         if (listViewObserver != null && didAddItemSuccessfully)
         {
            string itemAsString = item.ToString();
            listViewObserver.Insert(itemAsString, itemAsString, 
               InvocationMethod.BeginInvoke, null);
         }
         return didAddItemSuccessfully;
      }

      /// <summary>
      /// Removes the specified item from the HashSet&lt;T>. Once removed, this item will be removed from the ListView observer.
      /// </summary>
      /// <param name="item">The element to remove from the HashSet&lt;T>.</param>
      /// <returns>True if the element is removed successfully; otherwise, false. This method returns false if the element is not present in the HashSet&lt;T>.</returns>
      public bool Remove(T item)
      {
         bool didRemoveItemSuccessfully = hashSet.Remove(item);
         if (listViewObserver != null && didRemoveItemSuccessfully)
         {
            string itemAsString = item.ToString();
            listViewObserver.Remove(itemAsString, InvocationMethod.BeginInvoke);
         }
         return didRemoveItemSuccessfully;
      }

      /// <summary>
      /// Determines whether the HashSet&lt;T> contains the specified element.
      /// </summary>
      /// <param name="item">The element to locate in the HashSet&lt;T>.</param>
      /// <returns>True if the element is successfully located; otherwise, false.</returns>
      public bool Contains(T item)
      {
         bool doesContainItem = hashSet.Contains(item);
         return doesContainItem;
      }

      /// <summary>
      /// Removes all elements from the HashSet&lt;T>.
      /// </summary>
      public void Clear()
      {
         hashSet.Clear();
         if (listViewObserver != null)
         {
            listViewObserver.Items.Clear();
         }
      }

      /// <summary>
      /// Releases all resources used by the ListViewObservableThreadSafeHashSet&lt;T>.
      /// </summary>
      public void Dispose()
      {
         hashSet.Dispose();
         GC.SuppressFinalize(this);
      }
   }
}
